package org.nf.web.exception;

import cn.hutool.core.util.ReflectUtil;
import org.nf.web.annotation.ExceptionAdvice;
import org.nf.web.annotation.ExceptionHandler;
import org.nf.web.config.Configure;
import org.nf.web.servlet.HandlerExceptionResolver;
import org.nf.web.servlet.View;
import org.nf.web.view.DefaultView;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 基于注解的全局异常解析器
 *
 * @author zhu
 * @date 2024-05-21
 */
public class AnnotationHandlerExceptionResolver implements HandlerExceptionResolver {

    /**
     * 存放所有带有@ExceptionHandler注解的异常处理方法
     */
    private final List<Method> handlerExMethods = new ArrayList<>();

    @Override
    public void init(Configure configure) {
        Set<Class<?>> classes = configure.getClasses();
        parseHandlerExMethods(classes);
        // 对集合进行排序
        sortExMethods();
    }

    /**
     * 扫描带有 @ExceptionHandler
     *
     * @param classes classes 所有的class
     */
    private void parseHandlerExMethods(Set<Class<?>> classes) {
        classes.forEach(clazz -> {
            if (clazz.isAnnotationPresent(ExceptionAdvice.class)) {
                for (Method method : clazz.getMethods()) {
                    if (method.isAnnotationPresent(ExceptionHandler.class)) {
                        handlerExMethods.add(method);
                    }
                }
            }
        });
    }

    @Override
    public View resolveException(Throwable t) {
        View view = null;
        for (Method method : handlerExMethods) {
            // 获取注解的异常Class对象
            Class<?> exClass = method.getAnnotation(ExceptionHandler.class).value();
            // 判断异常对象的匹配
            if (exClass.isAssignableFrom(t.getClass())){
                // 调用异常处理方法
                Object obj = invokeHandlerExMethods(method, t);
                // 解析为视图
                view = resolverView(obj);
                break;
            }
        }
        return view;
    }

    /**
     * 调用全局异常处理方法
     *
     * @param method
     * @param t
     * @return
     */
    private Object invokeHandlerExMethods(Method method, Throwable t) {
        // 创建异常处理类的实例
        Object instance = ReflectUtil.newInstance(method.getDeclaringClass());
        // 调用异常处理方法
        return ReflectUtil.invoke(instance, method, t);
    }

    /**
     * 解析为视图对象
     *
     * @param obj 异常处理方法的返回值
     * @return 视图对象
     */
    private View resolverView(Object obj) {
        if (obj != null){
            return (obj instanceof View) ? (View)obj : new DefaultView(obj);
        }
        return null;
    }

    /**
     * 将异常按照从小到大的级别进行排序
     */
    @SuppressWarnings("all")
    private void sortExMethods() {
        handlerExMethods.sort((m1,m2) -> {
            return m1.getAnnotation(ExceptionHandler.class).value()
                    .isAssignableFrom(m2.getAnnotation(ExceptionHandler.class).value()) ? 1 : -1;
        });
    }
}
